home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / file / fileutil.13 / fileutil / fileutils-3.13 / src / ls.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-08  |  65.8 KB  |  2,754 lines

  1. /* `dir', `vdir' and `ls' directory listing programs for GNU.
  2.    Copyright (C) 85, 88, 90, 91, 95, 1996 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software Foundation,
  16.    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
  17.  
  18. /* If the macro MULTI_COL is defined,
  19.    the multi-column format is the default regardless
  20.    of the type of output device.
  21.    This is for the `dir' program.
  22.  
  23.    If the macro LONG_FORMAT is defined,
  24.    the long format is the default regardless of the
  25.    type of output device.
  26.    This is for the `vdir' program.
  27.  
  28.    If neither is defined,
  29.    the output format depends on whether the output
  30.    device is a terminal.
  31.    This is for the `ls' program. */
  32.  
  33. /* Written by Richard Stallman and David MacKenzie.  */
  34.  
  35. /* Color support by Peter Anvin <Peter.Anvin@linux.org> and Dennis
  36.    Flaherty <dennisf@denix.elk.miles.com> based on original patches by
  37.    Greg Lee <lee@uhunix.uhcc.hawaii.edu>.  */
  38.  
  39. #ifdef _AIX
  40.  #pragma alloca
  41. #endif
  42.  
  43. #include <config.h>
  44. #include <sys/types.h>
  45.  
  46. #include <termios.h>
  47. #ifdef GWINSZ_IN_SYS_IOCTL
  48. # include <sys/ioctl.h>
  49. #endif
  50.  
  51. #include <stdio.h>
  52. #include <grp.h>
  53. #include <pwd.h>
  54. #include <getopt.h>
  55.  
  56. #if HAVE_LIMITS_H
  57. /* limits.h must come before system.h because limits.h on some systems
  58.    undefs PATH_MAX, whereas system.h includes pathmax.h which sets
  59.    PATH_MAX.  */
  60. # include <limits.h>
  61. #endif
  62.  
  63. #include "system.h"
  64. #include <fnmatch.h>
  65.  
  66. #include "obstack.h"
  67. #include "ls.h"
  68. #include "error.h"
  69. #include "argmatch.h"
  70. #include "xstrtol.h"
  71.  
  72. #define obstack_chunk_alloc xmalloc
  73. #define obstack_chunk_free free
  74.  
  75. #ifndef INT_MAX
  76. # define INT_MAX 2147483647
  77. #endif
  78.  
  79. /* Return an int indicating the result of comparing two longs. */
  80. #if (INT_MAX <= 65535)
  81. # define longdiff(a, b) ((a) < (b) ? -1 : (a) > (b) ? 1 : 0)
  82. #else
  83. # define longdiff(a, b) ((a) - (b))
  84. #endif
  85.  
  86. /* The maximum number of digits required to print an inode number
  87.    in an unsigned format.  */
  88. #ifndef INODE_DIGITS
  89. # define INODE_DIGITS 7
  90. #endif
  91.  
  92. enum filetype
  93.   {
  94.     symbolic_link,
  95.     directory,
  96.     arg_directory,        /* Directory given as command line arg. */
  97.     normal            /* All others. */
  98.   };
  99.  
  100. struct fileinfo
  101.   {
  102.     /* The file name. */
  103.     char *name;
  104.  
  105.     struct stat stat;
  106.  
  107.     /* For symbolic link, name of the file linked to, otherwise zero. */
  108.     char *linkname;
  109.  
  110.     /* For symbolic link and long listing, st_mode of file linked to, otherwise
  111.        zero. */
  112.     unsigned int linkmode;
  113.  
  114.     /* For symbolic link and color printing, 1 if linked-to file
  115.        exits, otherwise 0.  */
  116.     int linkok;
  117.  
  118.     enum filetype filetype;
  119.   };
  120.  
  121. #define LEN_STR_PAIR(s) sizeof (s) - 1, s
  122.  
  123. /* Null is a valid character in a color indicator (think about Epson
  124.    printers, for example) so we have to use a length/buffer string
  125.    type.  */
  126.  
  127. struct bin_str
  128.   {
  129.     unsigned int len;        /* Number of bytes */
  130.     char *string;        /* Pointer to the same */
  131.   };
  132.  
  133. #ifndef STDC_HEADERS
  134. char *ctime ();
  135. time_t time ();
  136. void free ();
  137. #endif
  138.  
  139. void mode_string ();
  140.  
  141. char *stpcpy ();
  142. char *xstrdup ();
  143. char *getgroup ();
  144. char *getuser ();
  145. char *xmalloc ();
  146. char *xrealloc ();
  147. void invalid_arg ();
  148.  
  149. static char *make_link_path __P ((const char *path, const char *linkname));
  150. static int compare_atime __P ((const struct fileinfo *file1,
  151.                    const struct fileinfo *file2));
  152. static int rev_cmp_atime __P ((const struct fileinfo *file2,
  153.                    const struct fileinfo *file1));
  154. static int compare_ctime __P ((const struct fileinfo *file1,
  155.                    const struct fileinfo *file2));
  156. static int rev_cmp_ctime __P ((const struct fileinfo *file2,
  157.                    const struct fileinfo *file1));
  158. static int compare_mtime __P ((const struct fileinfo *file1,
  159.                    const struct fileinfo *file2));
  160. static int rev_cmp_mtime __P ((const struct fileinfo *file2,
  161.                    const struct fileinfo *file1));
  162. static int compare_size __P ((const struct fileinfo *file1,
  163.                   const struct fileinfo *file2));
  164. static int rev_cmp_size __P ((const struct fileinfo *file2,
  165.                   const struct fileinfo *file1));
  166. static int compare_name __P ((const struct fileinfo *file1,
  167.                   const struct fileinfo *file2));
  168. static int rev_cmp_name __P ((const struct fileinfo *file2,
  169.                   const struct fileinfo *file1));
  170. static int compare_extension __P ((const struct fileinfo *file1,
  171.                    const struct fileinfo *file2));
  172. static int rev_cmp_extension __P ((const struct fileinfo *file2,
  173.                    const struct fileinfo *file1));
  174. static int decode_switches __P ((int argc, char **argv));
  175. static int file_interesting __P ((const struct dirent *next));
  176. static int gobble_file __P ((const char *name, int explicit_arg,
  177.                  const char *dirname));
  178. static int is_not_dot_or_dotdot __P ((const char *name));
  179. static void print_color_indicator __P ((const char *name, unsigned int mode,
  180.                     int linkok));
  181. static void put_indicator __P ((const struct bin_str *ind));
  182. static int length_of_file_name_and_frills __P ((const struct fileinfo *f));
  183. static void add_ignore_pattern __P ((const char *pattern));
  184. static void attach __P ((char *dest, const char *dirname, const char *name));
  185. static void clear_files __P ((void));
  186. static void extract_dirs_from_files __P ((const char *dirname, int recursive));
  187. static void get_link_name __P ((const char *filename, struct fileinfo *f));
  188. static void indent __P ((int from, int to));
  189. static void print_current_files __P ((void));
  190. static void print_dir __P ((const char *name, const char *realname));
  191. static void print_file_name_and_frills __P ((const struct fileinfo *f));
  192. static void print_horizontal __P ((void));
  193. static void print_long_format __P ((const struct fileinfo *f));
  194. static void print_many_per_line __P ((void));
  195. static void print_name_with_quoting __P ((const char *p, unsigned int mode,
  196.                       int linkok));
  197. static void print_type_indicator __P ((unsigned int mode));
  198. static void print_with_commas __P ((void));
  199. static void queue_directory __P ((const char *name, const char *realname));
  200. static void sort_files __P ((void));
  201. static void parse_ls_color __P ((void));
  202. static void usage __P ((int status));
  203.  
  204. /* The name the program was run with, stripped of any leading path. */
  205. char *program_name;
  206.  
  207. /* The table of files in the current directory:
  208.  
  209.    `files' points to a vector of `struct fileinfo', one per file.
  210.    `nfiles' is the number of elements space has been allocated for.
  211.    `files_index' is the number actually in use.  */
  212.  
  213. /* Address of block containing the files that are described.  */
  214.  
  215. static struct fileinfo *files;
  216.  
  217. /* Length of block that `files' points to, measured in files.  */
  218.  
  219. static int nfiles;
  220.  
  221. /* Index of first unused in `files'.  */
  222.  
  223. static int files_index;
  224.  
  225. /* Record of one pending directory waiting to be listed.  */
  226.  
  227. struct pending
  228.   {
  229.     char *name;
  230.     /* If the directory is actually the file pointed to by a symbolic link we
  231.        were told to list, `realname' will contain the name of the symbolic
  232.        link, otherwise zero. */
  233.     char *realname;
  234.     struct pending *next;
  235.   };
  236.  
  237. static struct pending *pending_dirs;
  238.  
  239. /* Current time (seconds since 1970).  When we are printing a file's time,
  240.    include the year if it is more than 6 months before this time.  */
  241.  
  242. static time_t current_time;
  243.  
  244. /* The number of digits to use for block sizes.
  245.    4, or more if needed for bigger numbers.  */
  246.  
  247. static int block_size_size;
  248.  
  249. /* Option flags */
  250.  
  251. /* long_format for lots of info, one per line.
  252.    one_per_line for just names, one per line.
  253.    many_per_line for just names, many per line, sorted vertically.
  254.    horizontal for just names, many per line, sorted horizontally.
  255.    with_commas for just names, many per line, separated by commas.
  256.  
  257.    -l, -1, -C, -x and -m control this parameter.  */
  258.  
  259. enum format
  260.   {
  261.     long_format,        /* -l */
  262.     one_per_line,        /* -1 */
  263.     many_per_line,        /* -C */
  264.     horizontal,            /* -x */
  265.     with_commas            /* -m */
  266.   };
  267.  
  268. static enum format format;
  269.  
  270. /* Type of time to print or sort by.  Controlled by -c and -u.  */
  271.  
  272. enum time_type
  273.   {
  274.     time_mtime,            /* default */
  275.     time_ctime,            /* -c */
  276.     time_atime            /* -u */
  277.   };
  278.  
  279. static enum time_type time_type;
  280.  
  281. /* print the full time, otherwise the standard unix heuristics. */
  282.  
  283. int full_time;
  284.  
  285. /* The file characteristic to sort by.  Controlled by -t, -S, -U, -X. */
  286.  
  287. enum sort_type
  288.   {
  289.     sort_none,            /* -U */
  290.     sort_name,            /* default */
  291.     sort_extension,        /* -X */
  292.     sort_time,            /* -t */
  293.     sort_size            /* -S */
  294.   };
  295.  
  296. static enum sort_type sort_type;
  297.  
  298. /* Direction of sort.
  299.    0 means highest first if numeric,
  300.    lowest first if alphabetic;
  301.    these are the defaults.
  302.    1 means the opposite order in each case.  -r  */
  303.  
  304. static int sort_reverse;
  305.  
  306. /* Nonzero means to NOT display group information.  -G  */
  307.  
  308. int inhibit_group;
  309.  
  310. /* Nonzero means print the user and group id's as numbers rather
  311.    than as names.  -n  */
  312.  
  313. static int numeric_users;
  314.  
  315. /* Nonzero means mention the size in 512 byte blocks of each file.  -s  */
  316.  
  317. static int print_block_size;
  318.  
  319. /* Nonzero means show file sizes in kilobytes instead of blocks
  320.    (the size of which is system-dependent).  -k */
  321.  
  322. static int kilobyte_blocks;
  323.  
  324. /* Precede each line of long output (per file) with a string like `m,n:'
  325.    where M is the number of characters after the `:' and before the
  326.    filename and N is the length of the filename.  Using this format,
  327.    Emacs' dired mode starts up twice as fast, and can handle all
  328.    strange characters in file names.  */
  329. static int dired;
  330.  
  331. /* `none' means don't mention the type of files.
  332.    `all' means mention the types of all files.
  333.    `not_programs' means do so except for executables.
  334.  
  335.    Controlled by -F and -p.  */
  336.  
  337. enum indicator_style
  338.   {
  339.     none,                      /* default */
  340.     all,                       /* -F */
  341.     not_programs               /* -p */
  342.   };
  343.  
  344. static enum indicator_style indicator_style;
  345.  
  346. /* Nonzero means use colors to mark types.  Also define the different
  347.    colors as well as the stuff for the LS_COLORS environment variable.
  348.    The LS_COLORS variable is now in a termcap-like format.  */
  349.  
  350. static int print_with_color;
  351.  
  352. enum color_type
  353.   {
  354.     color_never,        /* 0: default or --color=never */
  355.     color_always,        /* 1: --color=always */
  356.     color_if_tty        /* 2: --color=tty */
  357.   };
  358.  
  359. enum indicator_no
  360.   {
  361.     C_LEFT, C_RIGHT, C_END, C_NORM, C_FILE, C_DIR, C_LINK, C_FIFO, C_SOCK,
  362.     C_BLK, C_CHR, C_MISSING, C_ORPHAN, C_EXEC
  363.   };
  364.  
  365. static const char *const indicator_name[]=
  366.   {
  367.     "lc", "rc", "ec", "no", "fi", "di", "ln", "pi", "so",
  368.     "bd", "cd", "mi", "or", "ex", NULL
  369.   };
  370.  
  371. struct col_ext_type
  372.   {
  373.     struct bin_str ext;        /* The extension we're looking for */
  374.     struct bin_str seq;        /* The sequence to output when we do */
  375.     struct col_ext_type *next;    /* Next in list */
  376.   };
  377.  
  378. static struct bin_str color_indicator[] =
  379.   {
  380.     { LEN_STR_PAIR ("\033[") },        /* lc: Left of color sequence */
  381.     { LEN_STR_PAIR ("m") },        /* rc: Right of color sequence */
  382.     { 0, NULL },            /* ec: End color (replaces lc+no+rc) */
  383.     { LEN_STR_PAIR ("0") },        /* no: Normal */
  384.     { LEN_STR_PAIR ("0") },        /* fi: File: default */
  385.     { LEN_STR_PAIR ("01;34") },        /* di: Directory: bright blue */
  386.     { LEN_STR_PAIR ("01;36") },        /* ln: Symlink: bright cyan */
  387.     { LEN_STR_PAIR ("33") },        /* pi: Pipe: yellow/brown */
  388.     { LEN_STR_PAIR ("01;35") },        /* so: Socket: bright magenta */
  389.     { LEN_STR_PAIR ("01;33") },        /* bd: Block device: bright yellow */
  390.     { LEN_STR_PAIR ("01;33") },        /* cd: Char device: bright yellow */
  391.     { 0, NULL },            /* mi: Missing file: undefined */
  392.     { 0, NULL },            /* or: Orphanned symlink: undefined */
  393.     { LEN_STR_PAIR ("01;32") }        /* ex: Executable: bright green */
  394.   };
  395.  
  396. /* FIXME: comment  */
  397. struct col_ext_type *col_ext_list = NULL;
  398.  
  399. /* Buffer for color sequences */
  400. static char *color_buf;
  401.  
  402. /* Nonzero means mention the inode number of each file.  -i  */
  403.  
  404. static int print_inode;
  405.  
  406. /* Nonzero means when a symbolic link is found, display info on
  407.    the file linked to.  -L  */
  408.  
  409. static int trace_links;
  410.  
  411. /* Nonzero means when a directory is found, display info on its
  412.    contents.  -R  */
  413.  
  414. static int trace_dirs;
  415.  
  416. /* Nonzero means when an argument is a directory name, display info
  417.    on it itself.  -d  */
  418.  
  419. static int immediate_dirs;
  420.  
  421. /* Nonzero means don't omit files whose names start with `.'.  -A */
  422.  
  423. static int all_files;
  424.  
  425. /* Nonzero means don't omit files `.' and `..'
  426.    This flag implies `all_files'.  -a  */
  427.  
  428. static int really_all_files;
  429.  
  430. /* A linked list of shell-style globbing patterns.  If a non-argument
  431.    file name matches any of these patterns, it is omitted.
  432.    Controlled by -I.  Multiple -I options accumulate.
  433.    The -B option adds `*~' and `.*~' to this list.  */
  434.  
  435. struct ignore_pattern
  436.   {
  437.     const char *pattern;
  438.     struct ignore_pattern *next;
  439.   };
  440.  
  441. static struct ignore_pattern *ignore_patterns;
  442.  
  443. /* Nonzero means quote nongraphic chars in file names.  -b  */
  444.  
  445. static int quote_funny_chars;
  446.  
  447. /* Nonzero means output nongraphic chars in file names as `?'.  -q  */
  448.  
  449. static int qmark_funny_chars;
  450.  
  451. /* Nonzero means output each file name using C syntax for a string.
  452.    Always accompanied by `quote_funny_chars'.
  453.    This mode, together with -x or -C or -m,
  454.    and without such frills as -F or -s,
  455.    is guaranteed to make it possible for a program receiving
  456.    the output to tell exactly what file names are present.  -Q  */
  457.  
  458. static int quote_as_string;
  459.  
  460. /* The number of chars per hardware tab stop.  Setting this to zero
  461.    inhibits the use of TAB characters for separating columns.  -T */
  462. static int tabsize;
  463.  
  464. /* Nonzero means we are listing the working directory because no
  465.    non-option arguments were given. */
  466.  
  467. static int dir_defaulted;
  468.  
  469. /* Nonzero means print each directory name before listing it. */
  470.  
  471. static int print_dir_name;
  472.  
  473. /* The line length to use for breaking lines in many-per-line format.
  474.    Can be set with -w.  */
  475.  
  476. static int line_length;
  477.  
  478. /* If nonzero, the file listing format requires that stat be called on
  479.    each file. */
  480.  
  481. static int format_needs_stat;
  482.  
  483. /* The exit status to use if we don't get any fatal errors. */
  484.  
  485. static int exit_status;
  486.  
  487. /* If nonzero, display usage information and exit.  */
  488. static int show_help;
  489.  
  490. /* If nonzero, print the version on standard output and exit.  */
  491. static int show_version;
  492.  
  493. static struct option const long_options[] =
  494. {
  495.   {"all", no_argument, 0, 'a'},
  496.   {"escape", no_argument, 0, 'b'},
  497.   {"directory", no_argument, 0, 'd'},
  498.   {"dired", no_argument, 0, 'D'},
  499.   {"full-time", no_argument, &full_time, 1},
  500.   {"inode", no_argument, 0, 'i'},
  501.   {"kilobytes", no_argument, 0, 'k'},
  502.   {"numeric-uid-gid", no_argument, 0, 'n'},
  503.   {"no-group", no_argument, 0, 'G'},
  504.   {"hide-control-chars", no_argument, 0, 'q'},
  505.   {"reverse", no_argument, 0, 'r'},
  506.   {"size", no_argument, 0, 's'},
  507.   {"width", required_argument, 0, 'w'},
  508.   {"almost-all", no_argument, 0, 'A'},
  509.   {"ignore-backups", no_argument, 0, 'B'},
  510.   {"classify", no_argument, 0, 'F'},
  511.   {"file-type", no_argument, 0, 'F'},
  512.   {"ignore", required_argument, 0, 'I'},
  513.   {"dereference", no_argument, 0, 'L'},
  514.   {"literal", no_argument, 0, 'N'},
  515.   {"quote-name", no_argument, 0, 'Q'},
  516.   {"recursive", no_argument, 0, 'R'},
  517.   {"format", required_argument, 0, 12},
  518.   {"sort", required_argument, 0, 10},
  519.   {"tabsize", required_argument, 0, 'T'},
  520.   {"time", required_argument, 0, 11},
  521.   {"help", no_argument, &show_help, 1},
  522.   {"version", no_argument, &show_version, 1},
  523.   {"color", optional_argument, 0, 13},
  524.   {NULL, 0, NULL, 0}
  525. };
  526.  
  527. static char const *const format_args[] =
  528. {
  529.   "verbose", "long", "commas", "horizontal", "across",
  530.   "vertical", "single-column", 0
  531. };
  532.  
  533. static enum format const formats[] =
  534. {
  535.   long_format, long_format, with_commas, horizontal, horizontal,
  536.   many_per_line, one_per_line
  537. };
  538.  
  539. static char const *const sort_args[] =
  540. {
  541.   "none", "time", "size", "extension", 0
  542. };
  543.  
  544. static enum sort_type const sort_types[] =
  545. {
  546.   sort_none, sort_time, sort_size, sort_extension
  547. };
  548.  
  549. static char const *const time_args[] =
  550. {
  551.   "atime", "access", "use", "ctime", "status", 0
  552. };
  553.  
  554. /* This zero-based index is used solely with the --dired option.
  555.    When that option is in effect, this counter is incremented for each
  556.    character of output generated by this program so that the beginning
  557.    and ending indices (in that output) of every file name can be recorded
  558.    and later output themselves.  */
  559. static size_t dired_pos;
  560.  
  561. #define PUTCHAR(c) do {putchar ((c)); ++dired_pos;} while (0)
  562.  
  563. /* Write S to STREAM and increment DIRED_POS by S_LEN.  */
  564. #define FPUTS(s, stream, s_len) \
  565.     do {fputs ((s), (stream)); dired_pos += s_len;} while (0)
  566.  
  567. /* Like FPUTS, but for use when S is a literal string.  */
  568. #define FPUTS_LITERAL(s, stream) \
  569.     do {fputs ((s), (stream)); dired_pos += sizeof((s)) - 1;} while (0)
  570.  
  571. #define DIRED_INDENT()                            \
  572.     do                                    \
  573.       {                                    \
  574.     /* FIXME: remove the `&& format == long_format' clause.  */    \
  575.     if (dired && format == long_format)                \
  576.       FPUTS_LITERAL ("  ", stdout);                    \
  577.       }                                    \
  578.     while (0)
  579.  
  580. /* With --dired, store pairs of beginning and ending indices of filenames.  */
  581. static struct obstack dired_obstack;
  582.  
  583. /* With --dired, store pairs of beginning and ending indices of any
  584.    directory names that appear as headers (just before `total' line)
  585.    for lists of directory entries.  Such directory names are seen when
  586.    listing hierarchies using -R and when a directory is listed with at
  587.    least one other command line argument.  */
  588. static struct obstack subdired_obstack;
  589.  
  590. /* Save the current index on the specified obstack, OBS.  */
  591. #define PUSH_CURRENT_DIRED_POS(obs)                    \
  592.   do                                    \
  593.     {                                    \
  594.       /* FIXME: remove the `&& format == long_format' clause.  */    \
  595.       if (dired && format == long_format)                \
  596.     obstack_grow ((obs), &dired_pos, sizeof (dired_pos));        \
  597.     }                                    \
  598.   while (0)
  599.  
  600. static enum time_type const time_types[] =
  601. {
  602.   time_atime, time_atime, time_atime, time_ctime, time_ctime
  603. };
  604.  
  605. static char const *const color_args[] =
  606.   {
  607.     /* Note: "no" is a prefix of "none" so we don't include it.  */
  608.     /* force and none are for compatibility with another color-ls version */
  609.     "always", "yes", "force",
  610.     "never", "none",
  611.     "auto", "tty", "if-tty", 0
  612.   };
  613.  
  614. static enum color_type const color_types[] =
  615.   {
  616.     color_always, color_always, color_always,
  617.     color_never, color_never,
  618.     color_if_tty, color_if_tty, color_if_tty
  619.   };
  620.  
  621.  
  622. /* Write to standard output the string PREFIX followed by a space-separated
  623.    list of the integers stored in OS all on one line.  */
  624.  
  625. static void
  626. dired_dump_obstack (const char *prefix, struct obstack *os)
  627. {
  628.   int n_pos;
  629.  
  630.   n_pos = obstack_object_size (os) / sizeof (size_t);
  631.   if (n_pos > 0)
  632.     {
  633.       int i;
  634.       size_t *pos;
  635.  
  636.       pos = (size_t *) obstack_finish (os);
  637.       fputs (prefix, stdout);
  638.       for (i = 0; i < n_pos; i++)
  639.     printf (" %d", (int) pos[i]);
  640.       fputs ("\n", stdout);
  641.     }
  642. }
  643.  
  644. int
  645. main (int argc, char **argv)
  646. {
  647.   register int i;
  648.   register struct pending *thispend;
  649.  
  650.   program_name = argv[0];
  651.   setlocale (LC_ALL, "");
  652.   bindtextdomain (PACKAGE, LOCALEDIR);
  653.   textdomain (PACKAGE);
  654.  
  655.   exit_status = 0;
  656.   dir_defaulted = 1;
  657.   print_dir_name = 1;
  658.   pending_dirs = 0;
  659.   current_time = time ((time_t *) 0);
  660.  
  661.   i = decode_switches (argc, argv);
  662.  
  663.   if (show_version)
  664.     {
  665.       printf ("%s - %s\n",
  666.           (ls_mode == LS_LS ? "ls"
  667.            : (ls_mode == LS_MULTI_COL ? "dir" : "vdir")),
  668.           PACKAGE_VERSION);
  669.       exit (0);
  670.     }
  671.  
  672.   if (show_help)
  673.     usage (0);
  674.  
  675.   if (print_with_color)
  676.     parse_ls_color ();
  677.  
  678.   format_needs_stat = sort_type == sort_time || sort_type == sort_size
  679.     || format == long_format
  680.     || trace_links || trace_dirs || indicator_style != none
  681.     || print_block_size || print_inode || print_with_color;
  682.  
  683.   if (dired && format == long_format)
  684.     {
  685.       obstack_init (&dired_obstack);
  686.       obstack_init (&subdired_obstack);
  687.     }
  688.  
  689.   nfiles = 100;
  690.   files = (struct fileinfo *) xmalloc (sizeof (struct fileinfo) * nfiles);
  691.   files_index = 0;
  692.  
  693.   clear_files ();
  694.  
  695.   if (i < argc)
  696.     dir_defaulted = 0;
  697.   for (; i < argc; i++)
  698.     gobble_file (argv[i], 1, "");
  699.  
  700.   if (dir_defaulted)
  701.     {
  702.       if (immediate_dirs)
  703.     gobble_file (".", 1, "");
  704.       else
  705.     queue_directory (".", 0);
  706.     }
  707.  
  708.   if (files_index)
  709.     {
  710.       sort_files ();
  711.       if (!immediate_dirs)
  712.     extract_dirs_from_files ("", 0);
  713.       /* `files_index' might be zero now.  */
  714.     }
  715.   if (files_index)
  716.     {
  717.       print_current_files ();
  718.       if (pending_dirs)
  719.     PUTCHAR ('\n');
  720.     }
  721.   else if (pending_dirs && pending_dirs->next == 0)
  722.     print_dir_name = 0;
  723.  
  724.   while (pending_dirs)
  725.     {
  726.       thispend = pending_dirs;
  727.       pending_dirs = pending_dirs->next;
  728.       print_dir (thispend->name, thispend->realname);
  729.       free (thispend->name);
  730.       if (thispend->realname)
  731.     free (thispend->realname);
  732.       free (thispend);
  733.       print_dir_name = 1;
  734.     }
  735.  
  736.   if (dired && format == long_format)
  737.     {
  738.       /* No need to free these since we're about to exit.  */
  739.       dired_dump_obstack ("//DIRED//", &dired_obstack);
  740.       dired_dump_obstack ("//SUBDIRED//", &subdired_obstack);
  741.     }
  742.  
  743.   exit (exit_status);
  744. }
  745.  
  746. /* Set all the option flags according to the switches specified.
  747.    Return the index of the first non-option argument.  */
  748.  
  749. static int
  750. decode_switches (int argc, char **argv)
  751. {
  752.   register char *p;
  753.   int c;
  754.   int i;
  755.   long int tmp_long;
  756.  
  757.   qmark_funny_chars = 0;
  758.   quote_funny_chars = 0;
  759.  
  760.   /* initialize all switches to default settings */
  761.  
  762.   switch (ls_mode)
  763.     {
  764.     case LS_MULTI_COL:
  765.       /* This is for the `dir' program.  */
  766.       format = many_per_line;
  767.       quote_funny_chars = 1;
  768.       break;
  769.  
  770.     case LS_LONG_FORMAT:
  771.       /* This is for the `vdir' program.  */
  772.       format = long_format;
  773.       quote_funny_chars = 1;
  774.       break;
  775.  
  776.     case LS_LS:
  777.       /* This is for the `ls' program.  */
  778.       if (isatty (1))
  779.     {
  780.       format = many_per_line;
  781.       qmark_funny_chars = 1;
  782.     }
  783.       else
  784.     {
  785.       format = one_per_line;
  786.       qmark_funny_chars = 0;
  787.     }
  788.       break;
  789.  
  790.     default:
  791.       abort ();
  792.     }
  793.  
  794.   time_type = time_mtime;
  795.   full_time = 0;
  796.   sort_type = sort_name;
  797.   sort_reverse = 0;
  798.   numeric_users = 0;
  799.   print_block_size = 0;
  800.   kilobyte_blocks = getenv ("POSIXLY_CORRECT") == 0;
  801.   indicator_style = none;
  802.   print_inode = 0;
  803.   trace_links = 0;
  804.   trace_dirs = 0;
  805.   immediate_dirs = 0;
  806.   all_files = 0;
  807.   really_all_files = 0;
  808.   ignore_patterns = 0;
  809.   quote_as_string = 0;
  810.  
  811.   line_length = 80;
  812.   if ((p = getenv ("COLUMNS")))
  813.     {
  814.       if (xstrtol (p, NULL, 0, &tmp_long, NULL) == LONGINT_OK
  815.       && 0 < tmp_long && tmp_long <= INT_MAX)
  816.     {
  817.       line_length = (int) tmp_long;
  818.     }
  819.       else
  820.     {
  821.       error (0, 0,
  822.            _("ignoring invalid width in environment variable COLUMNS: %s"),
  823.          p);
  824.     }
  825.     }
  826.  
  827. #ifdef TIOCGWINSZ
  828.   {
  829.     struct winsize ws;
  830.  
  831.     if (ioctl (1, TIOCGWINSZ, &ws) != -1 && ws.ws_col != 0)
  832.       line_length = ws.ws_col;
  833.   }
  834. #endif
  835.  
  836.   /* Using the TABSIZE environment variable is not POSIX-approved.
  837.      Ignore it when POSIXLY_CORRECT is set.  */
  838.   tabsize = 8;
  839.   if (!getenv ("POSIXLY_CORRECT") && (p = getenv ("TABSIZE")))
  840.     {
  841.       if (xstrtol (p, NULL, 0, &tmp_long, NULL) == LONGINT_OK
  842.       && 0 <= tmp_long && tmp_long <= INT_MAX)
  843.     {
  844.       tabsize = (int) tmp_long;
  845.     }
  846.       else
  847.     {
  848.       error (0, 0,
  849.        _("ignoring invalid tab size in environment variable TABSIZE: %s"),
  850.          p);
  851.     }
  852.     }
  853.  
  854.   while ((c = getopt_long (argc, argv,
  855.                "abcdfgiklmnopqrstuw:xABCDFGI:LNQRST:UX1",
  856.                long_options, (int *) 0)) != EOF)
  857.     {
  858.       switch (c)
  859.     {
  860.     case 0:
  861.       break;
  862.  
  863.     case 'a':
  864.       all_files = 1;
  865.       really_all_files = 1;
  866.       break;
  867.  
  868.     case 'b':
  869.       quote_funny_chars = 1;
  870.       qmark_funny_chars = 0;
  871.       break;
  872.  
  873.     case 'c':
  874.       time_type = time_ctime;
  875.       sort_type = sort_time;
  876.       break;
  877.  
  878.     case 'd':
  879.       immediate_dirs = 1;
  880.       break;
  881.  
  882.     case 'f':
  883.       /* Same as enabling -a -U and disabling -l -s.  */
  884.       all_files = 1;
  885.       really_all_files = 1;
  886.       sort_type = sort_none;
  887.       /* disable -l */
  888.       if (format == long_format)
  889.         format = (isatty (1) ? many_per_line : one_per_line);
  890.       print_block_size = 0;    /* disable -s */
  891.       print_with_color = 0;    /* disable --color */
  892.       break;
  893.  
  894.     case 'g':
  895.       /* No effect.  For BSD compatibility. */
  896.       break;
  897.  
  898.     case 'i':
  899.       print_inode = 1;
  900.       break;
  901.  
  902.     case 'k':
  903.       kilobyte_blocks = 1;
  904.       break;
  905.  
  906.     case 'l':
  907.       format = long_format;
  908.       break;
  909.  
  910.     case 'm':
  911.       format = with_commas;
  912.       break;
  913.  
  914.     case 'n':
  915.       numeric_users = 1;
  916.       break;
  917.  
  918.     case 'o':  /* Just like -l, but don't display group info.  */
  919.       format = long_format;
  920.       inhibit_group = 1;
  921.       break;
  922.  
  923.     case 'p':
  924.       indicator_style = not_programs;
  925.       break;
  926.  
  927.     case 'q':
  928.       qmark_funny_chars = 1;
  929.       quote_funny_chars = 0;
  930.       break;
  931.  
  932.     case 'r':
  933.       sort_reverse = 1;
  934.       break;
  935.  
  936.     case 's':
  937.       print_block_size = 1;
  938.       break;
  939.  
  940.     case 't':
  941.       sort_type = sort_time;
  942.       break;
  943.  
  944.     case 'u':
  945.       time_type = time_atime;
  946.       break;
  947.  
  948.     case 'w':
  949.       if (xstrtol (optarg, NULL, 0, &tmp_long, NULL) != LONGINT_OK
  950.           || tmp_long <= 0 || tmp_long > INT_MAX)
  951.         error (1, 0, _("invalid line width: %s"), optarg);
  952.       line_length = (int) tmp_long;
  953.       break;
  954.  
  955.     case 'x':
  956.       format = horizontal;
  957.       break;
  958.  
  959.     case 'A':
  960.       all_files = 1;
  961.       break;
  962.  
  963.     case 'B':
  964.       add_ignore_pattern ("*~");
  965.       add_ignore_pattern (".*~");
  966.       break;
  967.  
  968.     case 'C':
  969.       format = many_per_line;
  970.       break;
  971.  
  972.     case 'D':
  973.       dired = 1;
  974.       break;
  975.  
  976.     case 'F':
  977.       indicator_style = all;
  978.       break;
  979.  
  980.     case 'G':        /* inhibit display of group info */
  981.       inhibit_group = 1;
  982.       break;
  983.  
  984.     case 'I':
  985.       add_ignore_pattern (optarg);
  986.       break;
  987.  
  988.     case 'L':
  989.       trace_links = 1;
  990.       break;
  991.  
  992.     case 'N':
  993.       quote_funny_chars = 0;
  994.       qmark_funny_chars = 0;
  995.       break;
  996.  
  997.     case 'Q':
  998.       quote_as_string = 1;
  999.       quote_funny_chars = 1;
  1000.       qmark_funny_chars = 0;
  1001.       break;
  1002.  
  1003.     case 'R':
  1004.       trace_dirs = 1;
  1005.       break;
  1006.  
  1007.     case 'S':
  1008.       sort_type = sort_size;
  1009.       break;
  1010.  
  1011.     case 'T':
  1012.       if (xstrtol (optarg, NULL, 0, &tmp_long, NULL) != LONGINT_OK
  1013.           || tmp_long < 0 || tmp_long > INT_MAX)
  1014.         error (1, 0, _("invalid tab size: %s"), optarg);
  1015.       tabsize = (int) tmp_long;
  1016.       break;
  1017.  
  1018.     case 'U':
  1019.       sort_type = sort_none;
  1020.       break;
  1021.  
  1022.     case 'X':
  1023.       sort_type = sort_extension;
  1024.       break;
  1025.  
  1026.     case '1':
  1027.       format = one_per_line;
  1028.       break;
  1029.  
  1030.     case 10:        /* --sort */
  1031.       i = argmatch (optarg, sort_args);
  1032.       if (i < 0)
  1033.         {
  1034.           invalid_arg (_("sort type"), optarg, i);
  1035.           usage (1);
  1036.         }
  1037.       sort_type = sort_types[i];
  1038.       break;
  1039.  
  1040.     case 11:        /* --time */
  1041.       i = argmatch (optarg, time_args);
  1042.       if (i < 0)
  1043.         {
  1044.           invalid_arg (_("time type"), optarg, i);
  1045.           usage (1);
  1046.         }
  1047.       time_type = time_types[i];
  1048.       break;
  1049.  
  1050.     case 12:        /* --format */
  1051.       i = argmatch (optarg, format_args);
  1052.       if (i < 0)
  1053.         {
  1054.           invalid_arg (_("format type"), optarg, i);
  1055.           usage (1);
  1056.         }
  1057.       format = formats[i];
  1058.       break;
  1059.  
  1060.     case 13:        /* --color */
  1061.       if (optarg)
  1062.         {
  1063.           i = argmatch (optarg, color_args);
  1064.           if (i < 0)
  1065.         {
  1066.           invalid_arg (_("colorization criterion"), optarg, i);
  1067.           usage (1);
  1068.         }
  1069.           i = color_types[i];
  1070.         }
  1071.       else
  1072.         {
  1073.           /* Using --color with no argument is equivalent to using
  1074.          --color=always.  */
  1075.           i = color_always;
  1076.         }
  1077.  
  1078.       print_with_color = (i == color_always
  1079.                   || (i == color_if_tty
  1080.                   && isatty (STDOUT_FILENO)));
  1081.  
  1082.       if (print_with_color)
  1083.         {
  1084.           /* Don't use TAB characters in output.  Some terminal
  1085.          emulators can't handle the combination of tabs and
  1086.          color codes on the same line.  */
  1087.           tabsize = 0;
  1088.         }
  1089.       break;
  1090.  
  1091.     default:
  1092.       usage (1);
  1093.     }
  1094.     }
  1095.  
  1096.   return optind;
  1097. }
  1098.  
  1099. /* Parse a string as part of the LS_COLORS variable; this may involve
  1100.    decoding all kinds of escape characters.  If equals_end is set an
  1101.    unescaped equal sign ends the string, otherwise only a : or \0
  1102.    does.  Returns the number of characters output, or -1 on failure.
  1103.  
  1104.    The resulting string is *not* null-terminated, but may contain
  1105.    embedded nulls.
  1106.  
  1107.    Note that both dest and src are char **; on return they point to
  1108.    the first free byte after the array and the character that ended
  1109.    the input string, respectively.  */
  1110.  
  1111. static int
  1112. get_funky_string (char **dest, const char **src, int equals_end)
  1113. {
  1114.   int num;            /* For numerical codes */
  1115.   int count;            /* Something to count with */
  1116.   enum {
  1117.     ST_GND, ST_BACKSLASH, ST_OCTAL, ST_HEX, ST_CARET, ST_END, ST_ERROR
  1118.   } state;
  1119.   const char *p;
  1120.   char *q;
  1121.  
  1122.   p = *src;            /* We don't want to double-indirect */
  1123.   q = *dest;            /* the whole darn time.  */
  1124.  
  1125.   count = 0;            /* No characters counted in yet.  */
  1126.   num = 0;
  1127.  
  1128.   state = ST_GND;        /* Start in ground state.  */
  1129.   while (state < ST_END)
  1130.     {
  1131.       switch (state)
  1132.     {
  1133.     case ST_GND:        /* Ground state (no escapes) */
  1134.       switch (*p)
  1135.         {
  1136.         case ':':
  1137.         case '\0':
  1138.           state = ST_END;    /* End of string */
  1139.           break;
  1140.         case '\\':
  1141.           state = ST_BACKSLASH; /* Backslash scape sequence */
  1142.           ++p;
  1143.           break;
  1144.         case '^':
  1145.           state = ST_CARET; /* Caret escape */
  1146.           ++p;
  1147.           break;
  1148.         case '=':
  1149.           if (equals_end)
  1150.         {
  1151.           state = ST_END; /* End */
  1152.           break;
  1153.         }
  1154.           /* else fall through */
  1155.         default:
  1156.           *(q++) = *(p++);
  1157.           ++count;
  1158.           break;
  1159.         }
  1160.       break;
  1161.  
  1162.     case ST_BACKSLASH:    /* Backslash escaped character */
  1163.       switch (*p)
  1164.         {
  1165.         case '0':
  1166.         case '1':
  1167.         case '2':
  1168.         case '3':
  1169.         case '4':
  1170.         case '5':
  1171.         case '6':
  1172.         case '7':
  1173.           state = ST_OCTAL;    /* Octal sequence */
  1174.           num = *p - '0';
  1175.           break;
  1176.         case 'x':
  1177.         case 'X':
  1178.           state = ST_HEX;    /* Hex sequence */
  1179.           num = 0;
  1180.           break;
  1181.         case 'a':        /* Bell */
  1182.           num = 7;        /* Not all C compilers know what \a means */
  1183.           break;
  1184.         case 'b':        /* Backspace */
  1185.           num = '\b';
  1186.           break;
  1187.         case 'e':        /* Escape */
  1188.           num = 27;
  1189.           break;
  1190.         case 'f':        /* Form feed */
  1191.           num = '\f';
  1192.           break;
  1193.         case 'n':        /* Newline */
  1194.           num = '\n';
  1195.           break;
  1196.         case 'r':        /* Carriage return */
  1197.           num = '\r';
  1198.           break;
  1199.         case 't':        /* Tab */
  1200.           num = '\t';
  1201.           break;
  1202.         case 'v':        /* Vtab */
  1203.           num = '\v';
  1204.           break;
  1205.         case '?':        /* Delete */
  1206.               num = 127;
  1207.           break;
  1208.         case '_':        /* Space */
  1209.           num = ' ';
  1210.           break;
  1211.         case '\0':        /* End of string */
  1212.           state = ST_ERROR;    /* Error! */
  1213.           break;
  1214.         default:        /* Escaped character like \ ^ : = */
  1215.           num = *p;
  1216.           break;
  1217.         }
  1218.       if (state == ST_BACKSLASH)
  1219.         {
  1220.           *(q++) = num;
  1221.           ++count;
  1222.           state = ST_GND;
  1223.         }
  1224.       ++p;
  1225.       break;
  1226.  
  1227.     case ST_OCTAL:        /* Octal sequence */
  1228.       if (*p < '0' || *p > '7')
  1229.         {
  1230.           *(q++) = num;
  1231.           ++count;
  1232.           state = ST_GND;
  1233.         }
  1234.       else
  1235.         num = (num << 3) + (*(p++) - '0');
  1236.       break;
  1237.  
  1238.     case ST_HEX:        /* Hex sequence */
  1239.       switch (*p)
  1240.         {
  1241.         case '0':
  1242.         case '1':
  1243.         case '2':
  1244.         case '3':
  1245.         case '4':
  1246.         case '5':
  1247.         case '6':
  1248.         case '7':
  1249.         case '8':
  1250.         case '9':
  1251.           num = (num << 4) + (*(p++) - '0');
  1252.           break;
  1253.         case 'a':
  1254.         case 'b':
  1255.         case 'c':
  1256.         case 'd':
  1257.         case 'e':
  1258.         case 'f':
  1259.           num = (num << 4) + (*(p++) - 'a') + 10;
  1260.           break;
  1261.         case 'A':
  1262.         case 'B':
  1263.         case 'C':
  1264.         case 'D':
  1265.         case 'E':
  1266.         case 'F':
  1267.           num = (num << 4) + (*(p++) - 'A') + 10;
  1268.           break;
  1269.         default:
  1270.           *(q++) = num;
  1271.           ++count;
  1272.           state = ST_GND;
  1273.           break;
  1274.         }
  1275.       break;
  1276.  
  1277.     case ST_CARET:        /* Caret escape */
  1278.       state = ST_GND;    /* Should be the next state... */
  1279.       if (*p >= '@' && *p <= '~')
  1280.         {
  1281.           *(q++) = *(p++) & 037;
  1282.           ++count;
  1283.         }
  1284.       else if ( *p == '?' )
  1285.         {
  1286.           *(q++) = 127;
  1287.           ++count;
  1288.         }
  1289.       else
  1290.         state = ST_ERROR;
  1291.       break;
  1292.  
  1293.     default:
  1294.       abort();
  1295.     }
  1296.     }
  1297.  
  1298.   *dest = q;
  1299.   *src = p;
  1300.  
  1301.   return state == ST_ERROR ? -1 : count;
  1302. }
  1303.  
  1304. static void
  1305. parse_ls_color (void)
  1306. {
  1307.   const char *p;        /* Pointer to character being parsed */
  1308.   char *buf;            /* color_buf buffer pointer */
  1309.   int state;            /* State of parser */
  1310.   int ind_no;            /* Indicator number */
  1311.   char label[3];        /* Indicator label */
  1312.   struct col_ext_type *ext;    /* Extension we are working on */
  1313.   struct col_ext_type *ext2;    /* Extra pointer */
  1314.  
  1315.   if ((p = getenv ("LS_COLORS")) == NULL || *p == '\0')
  1316.     return;
  1317.  
  1318.   ext = NULL;
  1319.   strcpy (label, "??");
  1320.  
  1321.   /* This is an overly conservative estimate, but any possible
  1322.      LS_COLORS string will *not* generate a color_buf longer than
  1323.      itself, so it is a safe way of allocating a buffer in
  1324.      advance.  */
  1325.   buf = color_buf = xstrdup (p);
  1326.  
  1327.   state = 1;
  1328.   while (state > 0)
  1329.     {
  1330.       switch (state)
  1331.     {
  1332.     case 1:        /* First label character */
  1333.       switch (*p)
  1334.         {
  1335.         case ':':
  1336.           ++p;
  1337.           break;
  1338.  
  1339.         case '*':
  1340.           /* Allocate new extension block and add to head of
  1341.          linked list (this way a later definition will
  1342.          override an earlier one, which can be useful for
  1343.          having terminal-specific defs override global).  */
  1344.  
  1345.           ext = (struct col_ext_type *)
  1346.         xmalloc (sizeof (struct col_ext_type));
  1347.           ext->next = col_ext_list;
  1348.           col_ext_list = ext;
  1349.  
  1350.           ++p;
  1351.           ext->ext.string = buf;
  1352.  
  1353.           state = (ext->ext.len =
  1354.                get_funky_string (&buf, &p, 1)) < 0 ? -1 : 4;
  1355.           break;
  1356.  
  1357.         case '\0':
  1358.           state = 0;    /* Done! */
  1359.           break;
  1360.  
  1361.         default:    /* Assume it is file type label */
  1362.           label[0] = *(p++);
  1363.           state = 2;
  1364.           break;
  1365.         }
  1366.       break;
  1367.  
  1368.     case 2:        /* Second label character */
  1369.       if (*p)
  1370.         {
  1371.           label[1] = *(p++);
  1372.           state = 3;
  1373.         }
  1374.       else
  1375.         state = -1;    /* Error */
  1376.       break;
  1377.  
  1378.     case 3:        /* Equal sign after indicator label */
  1379.       state = -1;    /* Assume failure... */
  1380.       if (*(p++) == '=')/* It *should* be... */
  1381.         {
  1382.           for (ind_no = 0; indicator_name[ind_no] != NULL; ++ind_no)
  1383.         {
  1384.           if (STREQ (label, indicator_name[ind_no]))
  1385.             {
  1386.               color_indicator[ind_no].string = buf;
  1387.               state = ((color_indicator[ind_no].len =
  1388.                 get_funky_string (&buf, &p, 0)) < 0 ? -1 : 1);
  1389.               break;
  1390.             }
  1391.         }
  1392.           if (state == -1)
  1393.         error (0, 0, _("unrecognized prefix: %s"), label);
  1394.         }
  1395.      break;
  1396.  
  1397.     case 4:        /* Equal sign after *.ext */
  1398.       if (*(p++) == '=')
  1399.         {
  1400.           ext->seq.string = buf;
  1401.           state = (ext->seq.len =
  1402.                get_funky_string (&buf, &p, 0)) < 0 ? -1 : 1;
  1403.         }
  1404.       else
  1405.         state = -1;
  1406.       break;
  1407.     }
  1408.     }
  1409.  
  1410.   if (state < 0)
  1411.     {
  1412.       struct col_ext_type *e;
  1413.  
  1414.       error (0, 0,
  1415.          _("unparsable value for LS_COLORS environment variable"));
  1416.       free (color_buf);
  1417.       for (e = col_ext_list; e != NULL ; /* empty */)
  1418.     {
  1419.       ext2 = e;
  1420.       e = e->next;
  1421.       free (ext2);
  1422.     }
  1423.       print_with_color = 0;
  1424.     }
  1425. }
  1426.  
  1427. /* Request that the directory named `name' have its contents listed later.
  1428.    If `realname' is nonzero, it will be used instead of `name' when the
  1429.    directory name is printed.  This allows symbolic links to directories
  1430.    to be treated as regular directories but still be listed under their
  1431.    real names. */
  1432.  
  1433. static void
  1434. queue_directory (const char *name, const char *realname)
  1435. {
  1436.   struct pending *new;
  1437.  
  1438.   new = (struct pending *) xmalloc (sizeof (struct pending));
  1439.   new->next = pending_dirs;
  1440.   pending_dirs = new;
  1441.   new->name = xstrdup (name);
  1442.   if (realname)
  1443.     new->realname = xstrdup (realname);
  1444.   else
  1445.     new->realname = 0;
  1446. }
  1447.  
  1448. /* Read directory `name', and list the files in it.
  1449.    If `realname' is nonzero, print its name instead of `name';
  1450.    this is used for symbolic links to directories. */
  1451.  
  1452. static void
  1453. print_dir (const char *name, const char *realname)
  1454. {
  1455.   register DIR *reading;
  1456.   register struct dirent *next;
  1457.   register int total_blocks = 0;
  1458.  
  1459.   errno = 0;
  1460.   reading = opendir (name);
  1461.   if (!reading)
  1462.     {
  1463.       error (0, errno, "%s", name);
  1464.       exit_status = 1;
  1465.       return;
  1466.     }
  1467.  
  1468.   /* Read the directory entries, and insert the subfiles into the `files'
  1469.      table.  */
  1470.  
  1471.   clear_files ();
  1472.  
  1473.   while ((next = readdir (reading)) != NULL)
  1474.     if (file_interesting (next))
  1475.       total_blocks += gobble_file (next->d_name, 0, name);
  1476.  
  1477.   if (CLOSEDIR (reading))
  1478.     {
  1479.       error (0, errno, "%s", name);
  1480.       exit_status = 1;
  1481.       /* Don't return; print whatever we got. */
  1482.     }
  1483.  
  1484.   /* Sort the directory contents.  */
  1485.   sort_files ();
  1486.  
  1487.   /* If any member files are subdirectories, perhaps they should have their
  1488.      contents listed rather than being mentioned here as files.  */
  1489.  
  1490.   if (trace_dirs)
  1491.     extract_dirs_from_files (name, 1);
  1492.  
  1493.   if (print_dir_name)
  1494.     {
  1495.       const char *dir;
  1496.  
  1497.       DIRED_INDENT ();
  1498.       dir = (realname ? realname : name);
  1499.       PUSH_CURRENT_DIRED_POS (&subdired_obstack);
  1500.       FPUTS (dir, stdout, strlen (dir));
  1501.       PUSH_CURRENT_DIRED_POS (&subdired_obstack);
  1502.       FPUTS_LITERAL (":\n", stdout);
  1503.     }
  1504.  
  1505.   if (format == long_format || print_block_size)
  1506.     {
  1507.       char buf[6 + 20 + 1 + 1];
  1508.  
  1509.       DIRED_INDENT ();
  1510.       sprintf (buf, "total %u\n", total_blocks);
  1511.       FPUTS (buf, stdout, strlen (buf));
  1512.     }
  1513.  
  1514.   if (files_index)
  1515.     print_current_files ();
  1516.  
  1517.   if (pending_dirs)
  1518.     PUTCHAR ('\n');
  1519. }
  1520.  
  1521. /* Add `pattern' to the list of patterns for which files that match are
  1522.    not listed.  */
  1523.  
  1524. static void
  1525. add_ignore_pattern (const char *pattern)
  1526. {
  1527.   register struct ignore_pattern *ignore;
  1528.  
  1529.   ignore = (struct ignore_pattern *) xmalloc (sizeof (struct ignore_pattern));
  1530.   ignore->pattern = pattern;
  1531.   /* Add it to the head of the linked list. */
  1532.   ignore->next = ignore_patterns;
  1533.   ignore_patterns = ignore;
  1534. }
  1535.  
  1536. /* Return nonzero if the file in `next' should be listed. */
  1537.  
  1538. static int
  1539. file_interesting (const struct dirent *next)
  1540. {
  1541.   register struct ignore_pattern *ignore;
  1542.  
  1543.   for (ignore = ignore_patterns; ignore; ignore = ignore->next)
  1544.     if (fnmatch (ignore->pattern, next->d_name, FNM_PERIOD) == 0)
  1545.       return 0;
  1546.  
  1547.   if (really_all_files
  1548.       || next->d_name[0] != '.'
  1549.       || (all_files
  1550.       && next->d_name[1] != '\0'
  1551.       && (next->d_name[1] != '.' || next->d_name[2] != '\0')))
  1552.     return 1;
  1553.  
  1554.   return 0;
  1555. }
  1556.  
  1557. /* Enter and remove entries in the table `files'.  */
  1558.  
  1559. /* Empty the table of files. */
  1560.  
  1561. static void
  1562. clear_files (void)
  1563. {
  1564.   register int i;
  1565.  
  1566.   for (i = 0; i < files_index; i++)
  1567.     {
  1568.       free (files[i].name);
  1569.       if (files[i].linkname)
  1570.     free (files[i].linkname);
  1571.     }
  1572.  
  1573.   files_index = 0;
  1574.   block_size_size = 4;
  1575. }
  1576.  
  1577. /* Add a file to the current table of files.
  1578.    Verify that the file exists, and print an error message if it does not.
  1579.    Return the number of blocks that the file occupies.  */
  1580.  
  1581. static int
  1582. gobble_file (const char *name, int explicit_arg, const char *dirname)
  1583. {
  1584.   register int blocks;
  1585.   register int val;
  1586.   register char *path;
  1587.  
  1588.   if (files_index == nfiles)
  1589.     {
  1590.       nfiles *= 2;
  1591.       files = (struct fileinfo *) xrealloc (files, sizeof (*files) * nfiles);
  1592.     }
  1593.  
  1594.   files[files_index].linkname = 0;
  1595.   files[files_index].linkmode = 0;
  1596.  
  1597.   if (explicit_arg || format_needs_stat)
  1598.     {
  1599.       /* `path' is the absolute pathname of this file. */
  1600.  
  1601.       if (name[0] == '/' || dirname[0] == 0)
  1602.     path = (char *) name;
  1603.       else
  1604.     {
  1605.       path = (char *) alloca (strlen (name) + strlen (dirname) + 2);
  1606.       attach (path, dirname, name);
  1607.     }
  1608.  
  1609.       if (trace_links)
  1610.     {
  1611.       val = stat (path, &files[files_index].stat);
  1612.       if (val < 0)
  1613.         /* Perhaps a symbolically-linked to file doesn't exist; stat
  1614.            the link instead. */
  1615.         val = lstat (path, &files[files_index].stat);
  1616.     }
  1617.       else
  1618.     val = lstat (path, &files[files_index].stat);
  1619.       if (val < 0)
  1620.     {
  1621.       error (0, errno, "%s", path);
  1622.       exit_status = 1;
  1623.       return 0;
  1624.     }
  1625.  
  1626. #ifdef S_ISLNK
  1627.       if (S_ISLNK (files[files_index].stat.st_mode)
  1628.       && (explicit_arg || format == long_format))
  1629.     {
  1630.       char *linkpath;
  1631.       struct stat linkstats;
  1632.  
  1633.       get_link_name (path, &files[files_index]);
  1634.       linkpath = make_link_path (path, files[files_index].linkname);
  1635.  
  1636.       /* Avoid following symbolic links when possible, ie, when
  1637.          they won't be traced and when no indicator is needed. */
  1638.       if (linkpath
  1639.           && ((explicit_arg && format != long_format)
  1640.           || indicator_style != none)
  1641.           && stat (linkpath, &linkstats) == 0)
  1642.         {
  1643.           /* Symbolic links to directories that are mentioned on the
  1644.              command line are automatically traced if not being
  1645.              listed as files.  */
  1646.           if (explicit_arg && format != long_format
  1647.           && S_ISDIR (linkstats.st_mode))
  1648.         {
  1649.           /* Substitute the linked-to directory's name, but
  1650.              save the real name in `linkname' for printing.  */
  1651.           if (!immediate_dirs)
  1652.             {
  1653.               const char *tempname = name;
  1654.               name = linkpath;
  1655.               linkpath = files[files_index].linkname;
  1656.               files[files_index].linkname = (char *) tempname;
  1657.             }
  1658.           files[files_index].stat = linkstats;
  1659.         }
  1660.           else
  1661.         /* Get the linked-to file's mode for the filetype indicator
  1662.            in long listings.  */
  1663.         files[files_index].linkmode = linkstats.st_mode;
  1664.         }
  1665.       if (linkpath)
  1666.         free (linkpath);
  1667.     }
  1668. #endif
  1669.  
  1670. #ifdef S_ISLNK
  1671.       if (S_ISLNK (files[files_index].stat.st_mode))
  1672.     files[files_index].filetype = symbolic_link;
  1673.       else
  1674. #endif
  1675.       if (S_ISDIR (files[files_index].stat.st_mode))
  1676.     {
  1677.       if (explicit_arg && !immediate_dirs)
  1678.         files[files_index].filetype = arg_directory;
  1679.       else
  1680.         files[files_index].filetype = directory;
  1681.     }
  1682.       else
  1683.     files[files_index].filetype = normal;
  1684.  
  1685.       blocks = convert_blocks (ST_NBLOCKS (files[files_index].stat),
  1686.                    kilobyte_blocks);
  1687.       if (blocks >= 10000 && block_size_size < 5)
  1688.     block_size_size = 5;
  1689.       if (blocks >= 100000 && block_size_size < 6)
  1690.     block_size_size = 6;
  1691.       if (blocks >= 1000000 && block_size_size < 7)
  1692.     block_size_size = 7;
  1693.     }
  1694.   else
  1695.     blocks = 0;
  1696.  
  1697.   files[files_index].name = xstrdup (name);
  1698.   files_index++;
  1699.  
  1700.   return blocks;
  1701. }
  1702.  
  1703. #ifdef S_ISLNK
  1704.  
  1705. /* Put the name of the file that `filename' is a symbolic link to
  1706.    into the `linkname' field of `f'. */
  1707.  
  1708. static void
  1709. get_link_name (const char *filename, struct fileinfo *f)
  1710. {
  1711.   char *linkbuf;
  1712.   register int linksize;
  1713.  
  1714.   linkbuf = (char *) alloca (PATH_MAX + 2);
  1715.   /* Some automounters give incorrect st_size for mount points.
  1716.      I can't think of a good workaround for it, though.  */
  1717.   linksize = readlink (filename, linkbuf, PATH_MAX + 1);
  1718.   if (linksize < 0)
  1719.     {
  1720.       error (0, errno, "%s", filename);
  1721.       exit_status = 1;
  1722.     }
  1723.   else
  1724.     {
  1725.       linkbuf[linksize] = '\0';
  1726.       f->linkname = xstrdup (linkbuf);
  1727.     }
  1728. }
  1729.  
  1730. /* If `linkname' is a relative path and `path' contains one or more
  1731.    leading directories, return `linkname' with those directories
  1732.    prepended; otherwise, return a copy of `linkname'.
  1733.    If `linkname' is zero, return zero. */
  1734.  
  1735. static char *
  1736. make_link_path (const char *path, const char *linkname)
  1737. {
  1738.   char *linkbuf;
  1739.   int bufsiz;
  1740.  
  1741.   if (linkname == 0)
  1742.     return 0;
  1743.  
  1744.   if (*linkname == '/')
  1745.     return xstrdup (linkname);
  1746.  
  1747.   /* The link is to a relative path.  Prepend any leading path
  1748.      in `path' to the link name. */
  1749.   linkbuf = strrchr (path, '/');
  1750.   if (linkbuf == 0)
  1751.     return xstrdup (linkname);
  1752.  
  1753.   bufsiz = linkbuf - path + 1;
  1754.   linkbuf = xmalloc (bufsiz + strlen (linkname) + 1);
  1755.   strncpy (linkbuf, path, bufsiz);
  1756.   strcpy (linkbuf + bufsiz, linkname);
  1757.   return linkbuf;
  1758. }
  1759. #endif
  1760.  
  1761. /* Remove any entries from `files' that are for directories,
  1762.    and queue them to be listed as directories instead.
  1763.    `dirname' is the prefix to prepend to each dirname
  1764.    to make it correct relative to ls's working dir.
  1765.    `recursive' is nonzero if we should not treat `.' and `..' as dirs.
  1766.    This is desirable when processing directories recursively.  */
  1767.  
  1768. static void
  1769. extract_dirs_from_files (const char *dirname, int recursive)
  1770. {
  1771.   register int i, j;
  1772.   register char *path;
  1773.   int dirlen;
  1774.  
  1775.   dirlen = strlen (dirname) + 2;
  1776.   /* Queue the directories last one first, because queueing reverses the
  1777.      order.  */
  1778.   for (i = files_index - 1; i >= 0; i--)
  1779.     if ((files[i].filetype == directory || files[i].filetype == arg_directory)
  1780.     && (!recursive || is_not_dot_or_dotdot (files[i].name)))
  1781.       {
  1782.     if (files[i].name[0] == '/' || dirname[0] == 0)
  1783.       {
  1784.         queue_directory (files[i].name, files[i].linkname);
  1785.       }
  1786.     else
  1787.       {
  1788.         path = (char *) xmalloc (strlen (files[i].name) + dirlen);
  1789.         attach (path, dirname, files[i].name);
  1790.         queue_directory (path, files[i].linkname);
  1791.         free (path);
  1792.       }
  1793.     if (files[i].filetype == arg_directory)
  1794.       free (files[i].name);
  1795.       }
  1796.  
  1797.   /* Now delete the directories from the table, compacting all the remaining
  1798.      entries.  */
  1799.  
  1800.   for (i = 0, j = 0; i < files_index; i++)
  1801.     if (files[i].filetype != arg_directory)
  1802.       files[j++] = files[i];
  1803.   files_index = j;
  1804. }
  1805.  
  1806. /* Return nonzero if `name' doesn't end in `.' or `..'
  1807.    This is so we don't try to recurse on `././././. ...' */
  1808.  
  1809. static int
  1810. is_not_dot_or_dotdot (const char *name)
  1811. {
  1812.   char *t;
  1813.  
  1814.   t = strrchr (name, '/');
  1815.   if (t)
  1816.     name = t + 1;
  1817.  
  1818.   if (name[0] == '.'
  1819.       && (name[1] == '\0'
  1820.       || (name[1] == '.' && name[2] == '\0')))
  1821.     return 0;
  1822.  
  1823.   return 1;
  1824. }
  1825.  
  1826. /* Sort the files now in the table.  */
  1827.  
  1828. static void
  1829. sort_files (void)
  1830. {
  1831.   int (*func) ();
  1832.  
  1833.   switch (sort_type)
  1834.     {
  1835.     case sort_none:
  1836.       return;
  1837.     case sort_time:
  1838.       switch (time_type)
  1839.     {
  1840.     case time_ctime:
  1841.       func = sort_reverse ? rev_cmp_ctime : compare_ctime;
  1842.       break;
  1843.     case time_mtime:
  1844.       func = sort_reverse ? rev_cmp_mtime : compare_mtime;
  1845.       break;
  1846.     case time_atime:
  1847.       func = sort_reverse ? rev_cmp_atime : compare_atime;
  1848.       break;
  1849.     default:
  1850.       abort ();
  1851.     }
  1852.       break;
  1853.     case sort_name:
  1854.       func = sort_reverse ? rev_cmp_name : compare_name;
  1855.       break;
  1856.     case sort_extension:
  1857.       func = sort_reverse ? rev_cmp_extension : compare_extension;
  1858.       break;
  1859.     case sort_size:
  1860.       func = sort_reverse ? rev_cmp_size : compare_size;
  1861.       break;
  1862.     default:
  1863.       abort ();
  1864.     }
  1865.  
  1866.   qsort (files, files_index, sizeof (struct fileinfo), func);
  1867. }
  1868.  
  1869. /* Comparison routines for sorting the files. */
  1870.  
  1871. static int
  1872. compare_ctime (const struct fileinfo *file1, const struct fileinfo *file2)
  1873. {
  1874.   return longdiff (file2->stat.st_ctime, file1->stat.st_ctime);
  1875. }
  1876.  
  1877. static int
  1878. rev_cmp_ctime (const struct fileinfo *file2, const struct fileinfo *file1)
  1879. {
  1880.   return longdiff (file2->stat.st_ctime, file1->stat.st_ctime);
  1881. }
  1882.  
  1883. static int
  1884. compare_mtime (const struct fileinfo *file1, const struct fileinfo *file2)
  1885. {
  1886.   return longdiff (file2->stat.st_mtime, file1->stat.st_mtime);
  1887. }
  1888.  
  1889. static int
  1890. rev_cmp_mtime (const struct fileinfo *file2, const struct fileinfo *file1)
  1891. {
  1892.   return longdiff (file2->stat.st_mtime, file1->stat.st_mtime);
  1893. }
  1894.  
  1895. static int
  1896. compare_atime (const struct fileinfo *file1, const struct fileinfo *file2)
  1897. {
  1898.   return longdiff (file2->stat.st_atime, file1->stat.st_atime);
  1899. }
  1900.  
  1901. static int
  1902. rev_cmp_atime (const struct fileinfo *file2, const struct fileinfo *file1)
  1903. {
  1904.   return longdiff (file2->stat.st_atime, file1->stat.st_atime);
  1905. }
  1906.  
  1907. static int
  1908. compare_size (const struct fileinfo *file1, const struct fileinfo *file2)
  1909. {
  1910.   return longdiff (file2->stat.st_size, file1->stat.st_size);
  1911. }
  1912.  
  1913. static int
  1914. rev_cmp_size (const struct fileinfo *file2, const struct fileinfo *file1)
  1915. {
  1916.   return longdiff (file2->stat.st_size, file1->stat.st_size);
  1917. }
  1918.  
  1919. static int
  1920. compare_name (const struct fileinfo *file1, const struct fileinfo *file2)
  1921. {
  1922.   return strcmp (file1->name, file2->name);
  1923. }
  1924.  
  1925. static int
  1926. rev_cmp_name (const struct fileinfo *file2, const struct fileinfo *file1)
  1927. {
  1928.   return strcmp (file1->name, file2->name);
  1929. }
  1930.  
  1931. /* Compare file extensions.  Files with no extension are `smallest'.
  1932.    If extensions are the same, compare by filenames instead. */
  1933.  
  1934. static int
  1935. compare_extension (const struct fileinfo *file1, const struct fileinfo *file2)
  1936. {
  1937.   register char *base1, *base2;
  1938.   register int cmp;
  1939.  
  1940.   base1 = strrchr (file1->name, '.');
  1941.   base2 = strrchr (file2->name, '.');
  1942.   if (base1 == 0 && base2 == 0)
  1943.     return strcmp (file1->name, file2->name);
  1944.   if (base1 == 0)
  1945.     return -1;
  1946.   if (base2 == 0)
  1947.     return 1;
  1948.   cmp = strcmp (base1, base2);
  1949.   if (cmp == 0)
  1950.     return strcmp (file1->name, file2->name);
  1951.   return cmp;
  1952. }
  1953.  
  1954. static int
  1955. rev_cmp_extension (const struct fileinfo *file2, const struct fileinfo *file1)
  1956. {
  1957.   register char *base1, *base2;
  1958.   register int cmp;
  1959.  
  1960.   base1 = strrchr (file1->name, '.');
  1961.   base2 = strrchr (file2->name, '.');
  1962.   if (base1 == 0 && base2 == 0)
  1963.     return strcmp (file1->name, file2->name);
  1964.   if (base1 == 0)
  1965.     return -1;
  1966.   if (base2 == 0)
  1967.     return 1;
  1968.   cmp = strcmp (base1, base2);
  1969.   if (cmp == 0)
  1970.     return strcmp (file1->name, file2->name);
  1971.   return cmp;
  1972. }
  1973.  
  1974. /* List all the files now in the table.  */
  1975.  
  1976. static void
  1977. print_current_files (void)
  1978. {
  1979.   register int i;
  1980.  
  1981.   switch (format)
  1982.     {
  1983.     case one_per_line:
  1984.       for (i = 0; i < files_index; i++)
  1985.     {
  1986.       print_file_name_and_frills (files + i);
  1987.       putchar ('\n');
  1988.     }
  1989.       break;
  1990.  
  1991.     case many_per_line:
  1992.       print_many_per_line ();
  1993.       break;
  1994.  
  1995.     case horizontal:
  1996.       print_horizontal ();
  1997.       break;
  1998.  
  1999.     case with_commas:
  2000.       print_with_commas ();
  2001.       break;
  2002.  
  2003.     case long_format:
  2004.       for (i = 0; i < files_index; i++)
  2005.     {
  2006.       print_long_format (files + i);
  2007.       PUTCHAR ('\n');
  2008.     }
  2009.       break;
  2010.     }
  2011. }
  2012.  
  2013. static void
  2014. print_long_format (const struct fileinfo *f)
  2015. {
  2016.   char modebuf[20];
  2017.   char timebuf[40];
  2018.  
  2019.   /* 7 fields that may (worst case: 64-bit integral values) require 20 bytes,
  2020.      1 10-character mode string,
  2021.      1 24-character time string,
  2022.      9 spaces, one following each of these fields,
  2023.      and 1 trailing NUL byte.  */
  2024.   char bigbuf[7 * 20 + 10 + 24 + 9 + 1];
  2025.   char *p;
  2026.   time_t when;
  2027.  
  2028.   mode_string (f->stat.st_mode, modebuf);
  2029.   modebuf[10] = '\0';
  2030.  
  2031.   switch (time_type)
  2032.     {
  2033.     case time_ctime:
  2034.       when = f->stat.st_ctime;
  2035.       break;
  2036.     case time_mtime:
  2037.       when = f->stat.st_mtime;
  2038.       break;
  2039.     case time_atime:
  2040.       when = f->stat.st_atime;
  2041.       break;
  2042.     }
  2043.  
  2044.   strcpy (timebuf, ctime (&when));
  2045.  
  2046.   if (full_time)
  2047.     timebuf[24] = '\0';
  2048.   else
  2049.     {
  2050.       if (current_time > when + 6L * 30L * 24L * 60L * 60L    /* Old. */
  2051.       || current_time < when - 60L * 60L)    /* In the future. */
  2052.     {
  2053.       /* The file is fairly old or in the future.
  2054.          POSIX says the cutoff is 6 months old;
  2055.          approximate this by 6*30 days.
  2056.          Allow a 1 hour slop factor for what is considered "the future",
  2057.          to allow for NFS server/client clock disagreement.
  2058.          Show the year instead of the time of day.  */
  2059.       strcpy (timebuf + 11, timebuf + 19);
  2060.     }
  2061.       timebuf[16] = 0;
  2062.     }
  2063.  
  2064.   p = bigbuf;
  2065.  
  2066.   if (print_inode)
  2067.     {
  2068.       sprintf (p, "%*lu ", INODE_DIGITS, (unsigned long) f->stat.st_ino);
  2069.       p += strlen (p);
  2070.     }
  2071.  
  2072.   if (print_block_size)
  2073.     {
  2074.       sprintf (p, "%*u ", block_size_size,
  2075.            (unsigned) convert_blocks (ST_NBLOCKS (f->stat),
  2076.                       kilobyte_blocks));
  2077.       p += strlen (p);
  2078.     }
  2079.  
  2080.   /* The space between the mode and the number of links is the POSIX
  2081.      "optional alternate access method flag". */
  2082.   sprintf (p, "%s %3u ", modebuf, (unsigned int) f->stat.st_nlink);
  2083.   p += strlen (p);
  2084.  
  2085.   if (numeric_users)
  2086.     sprintf (p, "%-8u ", (unsigned int) f->stat.st_uid);
  2087.   else
  2088.     sprintf (p, "%-8.8s ", getuser (f->stat.st_uid));
  2089.   p += strlen (p);
  2090.  
  2091.   if (!inhibit_group)
  2092.     {
  2093.       if (numeric_users)
  2094.     sprintf (p, "%-8u ", (unsigned int) f->stat.st_gid);
  2095.       else
  2096.     sprintf (p, "%-8.8s ", getgroup (f->stat.st_gid));
  2097.       p += strlen (p);
  2098.     }
  2099.  
  2100.   if (S_ISCHR (f->stat.st_mode) || S_ISBLK (f->stat.st_mode))
  2101.     sprintf (p, "%3u, %3u ", (unsigned) major (f->stat.st_rdev),
  2102.          (unsigned) minor (f->stat.st_rdev));
  2103.   else
  2104.     sprintf (p, "%8lu ", (unsigned long) f->stat.st_size);
  2105.   p += strlen (p);
  2106.  
  2107.   sprintf (p, "%s ", full_time ? timebuf : timebuf + 4);
  2108.   p += strlen (p);
  2109.  
  2110.   DIRED_INDENT ();
  2111.   FPUTS (bigbuf, stdout, p - bigbuf);
  2112.   PUSH_CURRENT_DIRED_POS (&dired_obstack);
  2113.   print_name_with_quoting (f->name, f->stat.st_mode, f->linkok);
  2114.   PUSH_CURRENT_DIRED_POS (&dired_obstack);
  2115.  
  2116.   if (f->filetype == symbolic_link)
  2117.     {
  2118.       if (f->linkname)
  2119.     {
  2120.       FPUTS_LITERAL (" -> ", stdout);
  2121.       print_name_with_quoting (f->linkname, f->linkmode, f->linkok-1);
  2122.       if (indicator_style != none)
  2123.         print_type_indicator (f->linkmode);
  2124.     }
  2125.     }
  2126.   else if (indicator_style != none)
  2127.     print_type_indicator (f->stat.st_mode);
  2128. }
  2129.  
  2130. /* Set QUOTED_LENGTH to strlen(P) and return NULL if P == quoted(P).
  2131.    Otherwise, return xmalloc'd storage containing the quoted version
  2132.    of P and set QUOTED_LENGTH to the length of the quoted P.  */
  2133.  
  2134. static char *
  2135. quote_filename (register const char *p, size_t *quoted_length)
  2136. {
  2137.   register unsigned char c;
  2138.   const char *p0 = p;
  2139.   char *quoted, *q;
  2140.   int found_quotable;
  2141.  
  2142.   if (!quote_as_string && !quote_funny_chars && !qmark_funny_chars)
  2143.     {
  2144.       *quoted_length = strlen (p);
  2145.       return NULL;
  2146.     }
  2147.  
  2148.   found_quotable = 0;
  2149.   for (c = *p; c; c = *++p)
  2150.     {
  2151.       if (quote_funny_chars)
  2152.     {
  2153.       switch (c)
  2154.         {
  2155.         case '\\':
  2156.         case '\n':
  2157.         case '\b':
  2158.         case '\r':
  2159.         case '\t':
  2160.         case '\f':
  2161.         case ' ':
  2162.         case '"':
  2163.           found_quotable = 1;
  2164.           break;
  2165.  
  2166.         default:
  2167.           if (!ISGRAPH (c))
  2168.         found_quotable = 1;
  2169.           break;
  2170.         }
  2171.     }
  2172.       else
  2173.     {
  2174.       if (!ISPRINT (c) && qmark_funny_chars)
  2175.         found_quotable = 1;
  2176.     }
  2177.       if (found_quotable)
  2178.     break;
  2179.     }
  2180.  
  2181.   if (!found_quotable && !quote_as_string)
  2182.     {
  2183.       *quoted_length = p - p0;
  2184.       return NULL;
  2185.     }
  2186.  
  2187.   p = p0;
  2188.   quoted = xmalloc (4 * strlen (p) + 1);
  2189.   q = quoted;
  2190.  
  2191. #define SAVECHAR(c) *q++ = (c)
  2192. #define SAVE_2_CHARS(c12) \
  2193.     do { *q++ = ((c12)[0]); \
  2194.      *q++ = ((c12)[1]); } while (0)
  2195.  
  2196.   if (quote_as_string)
  2197.     SAVECHAR ('"');
  2198.  
  2199.   while ((c = *p++))
  2200.     {
  2201.       if (quote_funny_chars)
  2202.     {
  2203.       switch (c)
  2204.         {
  2205.         case '\\':
  2206.           SAVE_2_CHARS ("\\\\");
  2207.           break;
  2208.  
  2209.         case '\n':
  2210.           SAVE_2_CHARS ("\\n");
  2211.           break;
  2212.  
  2213.         case '\b':
  2214.           SAVE_2_CHARS ("\\b");
  2215.           break;
  2216.  
  2217.         case '\r':
  2218.           SAVE_2_CHARS ("\\r");
  2219.           break;
  2220.  
  2221.         case '\t':
  2222.           SAVE_2_CHARS ("\\t");
  2223.           break;
  2224.  
  2225.         case '\f':
  2226.           SAVE_2_CHARS ("\\f");
  2227.           break;
  2228.  
  2229.         case ' ':
  2230.           SAVE_2_CHARS ("\\ ");
  2231.           break;
  2232.  
  2233.         case '"':
  2234.           SAVE_2_CHARS ("\\\"");
  2235.           break;
  2236.  
  2237.         default:
  2238.           if (ISGRAPH (c))
  2239.         SAVECHAR (c);
  2240.           else
  2241.         {
  2242.           char buf[5];
  2243.           sprintf (buf, "\\%03o", (unsigned int) c);
  2244.           q = stpcpy (q, buf);
  2245.         }
  2246.         }
  2247.     }
  2248.       else
  2249.     {
  2250.       if (ISPRINT (c))
  2251.         SAVECHAR (c);
  2252.       else if (!qmark_funny_chars)
  2253.         SAVECHAR (c);
  2254.       else
  2255.         SAVECHAR ('?');
  2256.     }
  2257.     }
  2258.  
  2259.   if (quote_as_string)
  2260.     SAVECHAR ('"');
  2261.  
  2262.   *quoted_length = q - quoted;
  2263.  
  2264.   SAVECHAR ('\0');
  2265.  
  2266.   return quoted;
  2267. }
  2268.  
  2269. static void
  2270. print_name_with_quoting (const char *p, unsigned int mode, int linkok)
  2271. {
  2272.   char *quoted;
  2273.   size_t quoted_length;
  2274.  
  2275.   if (print_with_color)
  2276.     print_color_indicator (p, mode, linkok);
  2277.  
  2278.   quoted = quote_filename (p, "ed_length);
  2279.   FPUTS (quoted != NULL ? quoted : p, stdout, quoted_length);
  2280.   if (quoted)
  2281.     free (quoted);
  2282.  
  2283.   if (print_with_color)
  2284.     {
  2285.       if (color_indicator[C_END].string != NULL)
  2286.     put_indicator (&color_indicator[C_END]);
  2287.       else
  2288.     {
  2289.       put_indicator (&color_indicator[C_LEFT]);
  2290.       put_indicator (&color_indicator[C_NORM]);
  2291.       put_indicator (&color_indicator[C_RIGHT]);
  2292.     }
  2293.     }
  2294. }
  2295.  
  2296. /* Print the file name of `f' with appropriate quoting.
  2297.    Also print file size, inode number, and filetype indicator character,
  2298.    as requested by switches.  */
  2299.  
  2300. static void
  2301. print_file_name_and_frills (const struct fileinfo *f)
  2302. {
  2303.   if (print_inode)
  2304.     printf ("%*lu ", INODE_DIGITS, (unsigned long) f->stat.st_ino);
  2305.  
  2306.   if (print_block_size)
  2307.     printf ("%*u ", block_size_size,
  2308.         (unsigned) convert_blocks (ST_NBLOCKS (f->stat),
  2309.                        kilobyte_blocks));
  2310.  
  2311.   print_name_with_quoting (f->name, f->stat.st_mode, f->linkok);
  2312.  
  2313.   if (indicator_style != none)
  2314.     print_type_indicator (f->stat.st_mode);
  2315. }
  2316.  
  2317. static void
  2318. print_type_indicator (unsigned int mode)
  2319. {
  2320.   if (S_ISDIR (mode))
  2321.     PUTCHAR ('/');
  2322.  
  2323. #ifdef S_ISLNK
  2324.   if (S_ISLNK (mode))
  2325.     PUTCHAR ('@');
  2326. #endif
  2327.  
  2328. #ifdef S_ISFIFO
  2329.   if (S_ISFIFO (mode))
  2330.     PUTCHAR ('|');
  2331. #endif
  2332.  
  2333. #ifdef S_ISSOCK
  2334.   if (S_ISSOCK (mode))
  2335.     PUTCHAR ('=');
  2336. #endif
  2337.  
  2338.   if (S_ISREG (mode) && indicator_style == all
  2339.       && (mode & (S_IEXEC | S_IXGRP | S_IXOTH)))
  2340.     PUTCHAR ('*');
  2341. }
  2342.  
  2343. static void
  2344. print_color_indicator (const char *name, unsigned int mode, int linkok)
  2345. {
  2346.   int type = C_FILE;
  2347.   struct col_ext_type *ext;    /* Color extension */
  2348.   size_t len;            /* Length of name */
  2349.  
  2350.   /* Is this a nonexistent file?  If so, linkok == -1.  */
  2351.  
  2352.   if (linkok == -1 && color_indicator[C_MISSING].string != NULL)
  2353.     {
  2354.       ext = NULL;
  2355.       type = C_MISSING;
  2356.     }
  2357.   else
  2358.     {
  2359.       /* Test if is is a recognized extension.  */
  2360.  
  2361.       len = strlen (name);
  2362.       name += len;        /* Pointer to final \0.  */
  2363.       for (ext = col_ext_list; ext != NULL; ext = ext->next)
  2364.     if (ext->ext.len <= len
  2365.         && strncmp (name - ext->ext.len, ext->ext.string,
  2366.             ext->ext.len) == 0)
  2367.       break;
  2368.  
  2369.       if (ext == NULL)
  2370.     {
  2371.       if (S_ISDIR (mode))
  2372.         type = C_DIR;
  2373.  
  2374. #ifdef S_ISLNK
  2375.       else if (S_ISLNK (mode))
  2376.         type = ((!linkok && color_indicator[C_ORPHAN].string)
  2377.             ? C_ORPHAN : C_LINK);
  2378. #endif
  2379.  
  2380. #ifdef S_ISFIFO
  2381.       else if (S_ISFIFO (mode))
  2382.         type = C_FIFO;
  2383. #endif
  2384.  
  2385. #ifdef S_ISSOCK
  2386.       else if (S_ISSOCK (mode))
  2387.         type = C_SOCK;
  2388. #endif
  2389.  
  2390. #ifdef S_ISBLK
  2391.       else if (S_ISBLK (mode))
  2392.         type = C_BLK;
  2393. #endif
  2394.  
  2395. #ifdef S_ISCHR
  2396.       else if (S_ISCHR (mode))
  2397.         type = C_CHR;
  2398. #endif
  2399.  
  2400.       if (type == C_FILE && (mode & (S_IEXEC|S_IEXEC>>3|S_IEXEC>>6)) != 0)
  2401.         type = C_EXEC;
  2402.     }
  2403.     }
  2404.  
  2405.   put_indicator (&color_indicator[C_LEFT]);
  2406.   put_indicator (ext ? &(ext->seq) : &color_indicator[type]);
  2407.   put_indicator (&color_indicator[C_RIGHT]);
  2408. }
  2409.  
  2410. /* Output a color indicator (which may contain nulls).  */
  2411. static void
  2412. put_indicator (const struct bin_str *ind)
  2413. {
  2414.   register int i;
  2415.   register char *p;
  2416.  
  2417.   p = ind->string;
  2418.  
  2419.   for (i = ind->len; i > 0; --i)
  2420.     putchar (*(p++));
  2421. }
  2422.  
  2423. static int
  2424. length_of_file_name_and_frills (const struct fileinfo *f)
  2425. {
  2426.   register char *p = f->name;
  2427.   register unsigned char c;
  2428.   register int len = 0;
  2429.  
  2430.   if (print_inode)
  2431.     len += INODE_DIGITS + 1;
  2432.  
  2433.   if (print_block_size)
  2434.     len += 1 + block_size_size;
  2435.  
  2436.   if (quote_as_string)
  2437.     len += 2;
  2438.  
  2439.   while ((c = *p++))
  2440.     {
  2441.       if (quote_funny_chars)
  2442.     {
  2443.       switch (c)
  2444.         {
  2445.         case '\\':
  2446.         case '\n':
  2447.         case '\b':
  2448.         case '\r':
  2449.         case '\t':
  2450.         case '\f':
  2451.         case ' ':
  2452.           len += 2;
  2453.           break;
  2454.  
  2455.         case '"':
  2456.           if (quote_as_string)
  2457.         len += 2;
  2458.           else
  2459.         len += 1;
  2460.           break;
  2461.  
  2462.         default:
  2463.           if (ISPRINT (c))
  2464.         len += 1;
  2465.           else
  2466.         len += 4;
  2467.         }
  2468.     }
  2469.       else
  2470.     len += 1;
  2471.     }
  2472.  
  2473.   if (indicator_style != none)
  2474.     {
  2475.       unsigned filetype = f->stat.st_mode;
  2476.  
  2477.       if (S_ISREG (filetype))
  2478.     {
  2479.       if (indicator_style == all
  2480.           && (f->stat.st_mode & (S_IEXEC | S_IEXEC >> 3 | S_IEXEC >> 6)))
  2481.         len += 1;
  2482.     }
  2483.       else if (S_ISDIR (filetype)
  2484. #ifdef S_ISLNK
  2485.            || S_ISLNK (filetype)
  2486. #endif
  2487. #ifdef S_ISFIFO
  2488.            || S_ISFIFO (filetype)
  2489. #endif
  2490. #ifdef S_ISSOCK
  2491.            || S_ISSOCK (filetype)
  2492. #endif
  2493.     )
  2494.     len += 1;
  2495.     }
  2496.  
  2497.   return len;
  2498. }
  2499.  
  2500. static void
  2501. print_many_per_line (void)
  2502. {
  2503.   int filesno;            /* Index into files. */
  2504.   int row;            /* Current row. */
  2505.   int max_name_length;        /* Length of longest file name + frills. */
  2506.   int name_length;        /* Length of each file name + frills. */
  2507.   int pos;            /* Current character column. */
  2508.   int cols;            /* Number of files across. */
  2509.   int rows;            /* Maximum number of files down. */
  2510.  
  2511.   /* Compute the maximum file name length.  */
  2512.   max_name_length = 0;
  2513.   for (filesno = 0; filesno < files_index; filesno++)
  2514.     {
  2515.       name_length = length_of_file_name_and_frills (files + filesno);
  2516.       if (name_length > max_name_length)
  2517.     max_name_length = name_length;
  2518.     }
  2519.  
  2520.   /* Allow at least two spaces between names.  */
  2521.   max_name_length += 2;
  2522.  
  2523.   /* Calculate the maximum number of columns that will fit. */
  2524.   cols = line_length / max_name_length;
  2525.   if (cols == 0)
  2526.     cols = 1;
  2527.   /* Calculate the number of rows that will be in each column except possibly
  2528.      for a short column on the right. */
  2529.   rows = files_index / cols + (files_index % cols != 0);
  2530.   /* Recalculate columns based on rows. */
  2531.   cols = files_index / rows + (files_index % rows != 0);
  2532.  
  2533.   for (row = 0; row < rows; row++)
  2534.     {
  2535.       filesno = row;
  2536.       pos = 0;
  2537.       /* Print the next row.  */
  2538.       while (1)
  2539.     {
  2540.       print_file_name_and_frills (files + filesno);
  2541.       name_length = length_of_file_name_and_frills (files + filesno);
  2542.  
  2543.       filesno += rows;
  2544.       if (filesno >= files_index)
  2545.         break;
  2546.  
  2547.       indent (pos + name_length, pos + max_name_length);
  2548.       pos += max_name_length;
  2549.     }
  2550.       putchar ('\n');
  2551.     }
  2552. }
  2553.  
  2554. static void
  2555. print_horizontal (void)
  2556. {
  2557.   int filesno;
  2558.   int max_name_length;
  2559.   int name_length;
  2560.   int cols;
  2561.   int pos;
  2562.  
  2563.   /* Compute the maximum file name length.  */
  2564.   max_name_length = 0;
  2565.   for (filesno = 0; filesno < files_index; filesno++)
  2566.     {
  2567.       name_length = length_of_file_name_and_frills (files + filesno);
  2568.       if (name_length > max_name_length)
  2569.     max_name_length = name_length;
  2570.     }
  2571.  
  2572.   /* Allow two spaces between names.  */
  2573.   max_name_length += 2;
  2574.  
  2575.   cols = line_length / max_name_length;
  2576.   if (cols == 0)
  2577.     cols = 1;
  2578.  
  2579.   pos = 0;
  2580.   name_length = 0;
  2581.  
  2582.   for (filesno = 0; filesno < files_index; filesno++)
  2583.     {
  2584.       if (filesno != 0)
  2585.     {
  2586.       if (filesno % cols == 0)
  2587.         {
  2588.           putchar ('\n');
  2589.           pos = 0;
  2590.         }
  2591.       else
  2592.         {
  2593.           indent (pos + name_length, pos + max_name_length);
  2594.           pos += max_name_length;
  2595.         }
  2596.     }
  2597.  
  2598.       print_file_name_and_frills (files + filesno);
  2599.  
  2600.       name_length = length_of_file_name_and_frills (files + filesno);
  2601.     }
  2602.   putchar ('\n');
  2603. }
  2604.  
  2605. static void
  2606. print_with_commas (void)
  2607. {
  2608.   int filesno;
  2609.   int pos, old_pos;
  2610.  
  2611.   pos = 0;
  2612.  
  2613.   for (filesno = 0; filesno < files_index; filesno++)
  2614.     {
  2615.       old_pos = pos;
  2616.  
  2617.       pos += length_of_file_name_and_frills (files + filesno);
  2618.       if (filesno + 1 < files_index)
  2619.     pos += 2;        /* For the comma and space */
  2620.  
  2621.       if (old_pos != 0 && pos >= line_length)
  2622.     {
  2623.       putchar ('\n');
  2624.       pos -= old_pos;
  2625.     }
  2626.  
  2627.       print_file_name_and_frills (files + filesno);
  2628.       if (filesno + 1 < files_index)
  2629.     {
  2630.       putchar (',');
  2631.       putchar (' ');
  2632.     }
  2633.     }
  2634.   putchar ('\n');
  2635. }
  2636.  
  2637. /* Assuming cursor is at position FROM, indent up to position TO.
  2638.    Use a TAB character instead of two or more spaces whenever possible.  */
  2639.  
  2640. static void
  2641. indent (int from, int to)
  2642. {
  2643.   while (from < to)
  2644.     {
  2645.       if (tabsize > 0 && to / tabsize > (from + 1) / tabsize)
  2646.     {
  2647.       putchar ('\t');
  2648.       from += tabsize - from % tabsize;
  2649.     }
  2650.       else
  2651.     {
  2652.       putchar (' ');
  2653.       from++;
  2654.     }
  2655.     }
  2656. }
  2657.  
  2658. /* Put DIRNAME/NAME into DEST, handling `.' and `/' properly. */
  2659.  
  2660. static void
  2661. attach (char *dest, const char *dirname, const char *name)
  2662. {
  2663.   const char *dirnamep = dirname;
  2664.  
  2665.   /* Copy dirname if it is not ".". */
  2666.   if (dirname[0] != '.' || dirname[1] != 0)
  2667.     {
  2668.       while (*dirnamep)
  2669.     *dest++ = *dirnamep++;
  2670.       /* Add '/' if `dirname' doesn't already end with it. */
  2671.       if (dirnamep > dirname && dirnamep[-1] != '/')
  2672.     *dest++ = '/';
  2673.     }
  2674.   while (*name)
  2675.     *dest++ = *name++;
  2676.   *dest = 0;
  2677. }
  2678.  
  2679. static void
  2680. usage (int status)
  2681. {
  2682.   if (status != 0)
  2683.     fprintf (stderr, _("Try `%s --help' for more information.\n"),
  2684.          program_name);
  2685.   else
  2686.     {
  2687.       printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
  2688.       printf (_("\
  2689. List information about the FILEs (the current directory by default).\n\
  2690. Sort entries alphabetically if none of -cftuSUX nor --sort.\n\
  2691. \n\
  2692.   -A, --almost-all           do not list implied . and ..\n\
  2693.   -a, --all                  do not hide entries starting with .\n\
  2694.   -B, --ignore-backups       do not list implied entries ending with ~\n\
  2695.   -b, --escape               print octal escapes for nongraphic characters\n\
  2696.   -C                         list entries by columns\n\
  2697.   -c                         sort by change time; with -l: show ctime\n\
  2698.       --color[=WHEN]         control whether color is used to distinguish file\n\
  2699.                                types.  WHEN may be `never', `always', or `auto'\n\
  2700.   -D, --dired                generate output designed for Emacs' dired mode\n\
  2701.   -d, --directory            list directory entries instead of contents\n\
  2702.   -F, --classify             append a character for typing each entry\n\
  2703.   -f                         do not sort, enable -aU, disable -lst\n\
  2704.       --format=WORD          across -x, commas -m, horizontal -x, long -l,\n\
  2705.                                single-column -1, verbose -l, vertical -C\n\
  2706.       --full-time            list both full date and full time\n"));
  2707.  
  2708.       printf (_("\
  2709.   -G, --no-group             inhibit display of group information\n\
  2710.   -g                         (ignored)\n\
  2711.   -I, --ignore=PATTERN       do not list implied entries matching shell PATTERN\n\
  2712.   -i, --inode                print index number of each file\n\
  2713.   -k, --kilobytes            use 1024 blocks, not 512 despite POSIXLY_CORRECT\n\
  2714.   -L, --dereference          list entries pointed to by symbolic links\n\
  2715.   -l                         use a long listing format\n\
  2716.   -m                         fill width with a comma separated list of entries\n\
  2717.   -N, --literal              print raw entry names (don't treat e.g. control\n\
  2718.                                characters specially)\n\
  2719.   -n, --numeric-uid-gid      list numeric UIDs and GIDs instead of names\n\
  2720.   -o                         use long listing format without group info\n\
  2721.   -p                         append a character for typing each entry\n\
  2722.   -Q, --quote-name           enclose entry names in double quotes\n\
  2723.   -q, --hide-control-chars   print ? instead of non graphic characters\n\
  2724.   -R, --recursive            list subdirectories recursively\n\
  2725.   -r, --reverse              reverse order while sorting\n\
  2726.   -S                         sort by file size\n"));
  2727.  
  2728.       printf (_("\
  2729.   -s, --size                 print block size of each file\n\
  2730.       --sort=WORD            ctime -c, extension -X, none -U, size -S,\n\
  2731.                                status -c, time -t\n\
  2732.       --time=WORD            atime -u, access -u, use -u\n\
  2733.   -T, --tabsize=COLS         assume tab stops at each COLS instead of 8\n\
  2734.   -t                         sort by modification time; with -l: show mtime\n\
  2735.   -U                         do not sort; list entries in directory order\n\
  2736.   -u                         sort by last access time; with -l: show atime\n\
  2737.   -w, --width=COLS           assume screen width instead of current value\n\
  2738.   -x                         list entries by lines instead of by columns\n\
  2739.   -X                         sort alphabetically by entry extension\n\
  2740.   -1                         list one file per line\n\
  2741.       --help                 display this help and exit\n\
  2742.       --version              output version information and exit\n\
  2743. \n\
  2744. By default, color is not used to distinguish types of files.  That is\n\
  2745. equivalent to using --color=none.  Using the --color option without the\n\
  2746. optional WHEN argument is equivalent to using --color=always.  With\n\
  2747. --color=auto, color codes are output only if standard output is connected\n\
  2748. to a terminal (tty).\n\
  2749. "
  2750.         ));
  2751.     }
  2752.   exit (status);
  2753. }
  2754.